import Vue,{PropOptions,VNode} from 'vue';
import Icon from '../icon';
import {add,multi} from '../../../util/common';
import {VueConstructor} from 'vue/types/vue';
/**
 * 值类型
 */
export type ValueType=''|number;
/**
 * 定义非响应数据
 * @property {ValueType} lastChangeValue 上一次change事件的值
 */
export interface NumberInputVue extends Vue{
	lastChangeValue:ValueType,
}
/**
 * 数字输入框
 * @author 唐国雄
 * @date 2021/6/22
 * 属性----------------------
 * v-model			当前值, ValueType
 * :disable			禁用, boolean
 * :format			格式化(失焦时)
 * :readonly		只读, boolean
 * :max				最大值, number
 * :min				最小值, number
 * :step			步长, number
 * :precision		精度, number
 * :allow-empty		是否允许空值, boolean
 * :lazy			懒校验范围, boolean
 * :hide-button		隐藏按钮, boolean
 * :step-control	步进控制, boolean
 * :placeholder		占位文本, string
 * :no-border		没有边框, boolean
 * :auto-focus		自动聚焦, boolean
 * 事件----------------------
 * @input			值改变, ValueType
 * @focus			聚焦
 * @blur			失焦
 * @change			只有没有聚焦时才触发, ValueType
 * 方法----------------------
 * increase(count:number=1)		增加count个步长
 * reduce(count:number=1)		减少count个步长
 */
export default (Vue as VueConstructor<NumberInputVue>).extend({
	name:'NumberInput',
	props:{
		//当前值
		value:{
			type:[Number,String],
			required:true,
			default:'',
			validator(v){
				if(typeof v==='string'){
					return v==='';
				}
				return true;
			}
		} as PropOptions<ValueType>,
		//格式化(失焦时)
		format:Function,
		//禁用
		disable:Boolean,
		//只读
		readonly:Boolean,
		//最大值
		max:Number,
		//最小值
		min:Number,
		//步长
		step:{
			type:Number,
			default:1,
			validator(v){
				return v>0;
			}
		},
		//精度
		precision:{
			type:Number,
			validator(v){
				return v>=0;
			}
		},
		//是否允许空值
		allowEmpty:Boolean,
		//懒校验范围
		lazy:Boolean,
		//隐藏按钮
		hideButton:Boolean,
		//步进控制
		stepControl:{
			type:Boolean,
			default:true,
		},
		//占位文本
		placeholder:String,
		//没有边框
		noBorder:Boolean,
		//自动聚焦
		autoFocus:Boolean,
	},
	data(){
		return {
			//是否聚焦数字输入框
			focus:false,
			//显示值
			showValue:this.value+'',
		};
	},
	computed:{
		classes():string{
			return 'lexmis-NumberInput'+
				(this.focus?' lexmis--focus':'')+
				(this.disable?' lexmis--disable':'')+
				(this.readonly?' lexmis--readonly':'')+
				(this.noBorder?' lexmis--noBorder':'');
		},
		//上箭头的class
		increaseClass():string{
			const {max,value,realStep}=this;
			if(
				this.disable||
				this.readonly||
				(max!==undefined&&add(value===''?this.emptyNumber:value,realStep)>max)
			){
				return 'lexmis--disable';
			}
			return '';
		},
		//下箭头的class
		reduceClass():string{
			const {min,value,realStep}=this;
			if(
				this.disable||
				this.readonly||
				(min!==undefined&&add(value===''?this.emptyNumber:value,-realStep)<min)
			){
				return 'lexmis--disable';
			}
			return '';
		},
		//实际步长
		realStep():number{
			if(this.precision!==undefined){
				const power=Math.pow(10,this.precision);
				return Math.round(this.step*power)/power;
			}
			return this.step;
		},
		//空值代表的数字
		emptyNumber():number{
			const {min,max}=this;
			let val=0;
			if(min!==undefined&&val<min){
				val=min;
			}
			if(max!==undefined&&val>max){
				val=max;
			}
			return val;
		},
		//空值代表的值
		emptyValue():ValueType{
			if(this.allowEmpty){
				return '';
			}
			return this.emptyNumber;
		}
	},
	mounted(){
		this.$nextTick(function(){
			if(this.autoFocus){
				(this.$refs.input as HTMLElement).focus({preventScroll:true});
			}
		});
	},
	activated(){
		if(this.autoFocus){
			(this.$refs.input as HTMLElement).focus({preventScroll:true});
		}
	},
	watch:{
		value(val){
			if(!this.setValue(val)){
				this.$_lexmis_onchange(val);
				if(val!==Number(this.showValue)){
					this.showValue=val+'';
				}
			}
		},
	},
	created(){
		this.$watch(function(){
			return `${this.min}_${this.max}_${this.precision}_${this.allowEmpty}`;
		},function(){
			this.setValue(this.value);
		});
		this.lastChangeValue=this.value;
		this.setValue(this.value);
	},
	methods:{
		$_lexmis_onchange(val:ValueType){
			if(!this.focus&&val!==this.lastChangeValue){
				this.lastChangeValue=val;
				this.$emit('change',val);
			}
		},
		$_lexmis_increase(){
			if(this.disable||this.readonly){
				return;
			}
			this.increase(1);
		},
		$_lexmis_reduce(){
			if(this.disable||this.readonly){
				return;
			}
			this.reduce(1);
		},
		increase(count:number=1){
			if(this.realStep===0){
				console.error('step被计算为0!');
				return;
			}
			const val=add(this.value===''?this.emptyNumber:this.value,multi(this.realStep,count));
			const max=this.max;
			if(max===undefined||val<=max){
				this.$emit('input',val);
			}
		},
		reduce(count:number=1){
			if(this.realStep===0){
				console.error('step被计算为0!');
				return;
			}
			const val=add(this.value===''?this.emptyNumber:this.value,-multi(this.realStep,count));
			const min=this.min;
			if(min===undefined||val>=min){
				this.$emit('input',val);
			}
		},
		/**
		 * 设置当前值
		 * @param {ValueType} val 设置的值
		 * @return {boolean} 是否设置成功
		 */
		setValue(val:ValueType):boolean{
			if(val===''){
				if(this.emptyValue!==this.value){
					this.$emit('input',this.emptyValue);
					return true;
				}
			}else{
				const {min,max,precision}=this;
				if(precision!==undefined){
					const power=Math.pow(10,precision);
					val=Math.round(val*power)/power;
				}
				if(min!==undefined&&val<min){
					val=min;
				}
				if(max!==undefined&&val>max){
					val=max;
				}
				if(val!==this.value){
					this.$emit('input',val);
					return true;
				}
			}
			return false;
		},
	},
	render(h):VNode{
		return h('div',{
			staticClass:this.classes,
		},[
			h('input',{
				ref:'input',
				attrs:{
					readonly:this.readonly,
				},
				domProps:{
					value:this.focus
						?this.showValue
						:this.format
							?this.format(this.value)
							:this.value,
					type:'text',
					placeholder:this.placeholder,
					disabled:this.disable,
				},
				on:{
					input:(e:InputEvent) => {
						let inputVal=(e.target as HTMLInputElement).value;
						if(inputVal){
							let val=Number(inputVal);
							if(isFinite(val)){
								if(inputVal.indexOf(val+'')===-1){
									//精度损失
									this.$forceUpdate();
									return;
								}
								const {min,max,precision}=this;
								if(precision!==undefined){
									const pos=inputVal.indexOf('.');
									if(pos!==-1&&inputVal.length-pos-1>precision){
										//超出精度, 重置
										this.$forceUpdate();
										return;
									}
								}
								if(min!==undefined&&val<min){
									val=min;
									if(!this.lazy){
										inputVal=min+'';
									}
								}
								if(max!==undefined&&val>max){
									val=max;
									if(!this.lazy){
										inputVal=max+'';
									}
								}
								if(val!==this.value){
									this.$emit('input',val);
								}
								//处理无效的前缀0
								const noPrefixZero=inputVal.replace(/^(-)?0+(?!\.)(.+)$/,'$1$2');
								if(noPrefixZero!==this.showValue){
									this.$nextTick(function(){
										this.showValue=noPrefixZero;
									});
								}else{
									//输入框含有无效的前缀0, 重置
									this.$forceUpdate();
								}
							}else if(inputVal==='-'){
								this.showValue='-';
							}else{
								//错误输入, 重置
								this.$forceUpdate();
							}
						}else{
							if(this.emptyValue!==this.value){
								this.$emit('input',this.emptyValue);
							}
							this.$nextTick(function(){
								this.showValue='';
							});
						}
					},
					focus:() => {
						this.showValue=this.value+'';
						this.focus=true;
						this.$emit('focus');
					},
					blur:() => {
						this.focus=false;
						this.$_lexmis_onchange(this.value);
						this.$emit('blur');
					},
					keydown:(e:KeyboardEvent) => {
						let {key,ctrlKey}=e;
						key=key.toLowerCase();
						if(key==='arrowup'&&this.stepControl){
							this.$_lexmis_increase();
						}else if(key==='arrowdown'&&this.stepControl){
							this.$_lexmis_reduce();
						}
						if(
							['1','2','3','4','5','6','7','8','9','0','.','-','arrowleft','arrowright','backspace','delete','tab','a','c','v']
								.indexOf(key)===-1||
							(key==='.'&&this.precision===0)||
							(key==='-'&&this.min>=0)||
							(key==='a'&&!ctrlKey)||
							(key==='c'&&!ctrlKey)||
							(key==='v'&&!ctrlKey)
						){
							//以上按键以外不能输入
							e.preventDefault();
						}
					},
					wheel:(e:WheelEvent) => {
						if(this.focus&&this.stepControl){
							const {deltaY}=e;
							if(deltaY>0){
								this.$_lexmis_reduce();
							}else if(deltaY<0){
								this.$_lexmis_increase();
							}
							e.preventDefault();
						}
					}
				}
			}),
			!this.hideButton
				?h('div',{
					staticClass:'lexmis_control',
				},[
					h(Icon,{
						staticClass:this.increaseClass,
						props:{
							name:'expand_less'
						},
						on:{
							click:this.$_lexmis_increase
						}
					}),
					h(Icon,{
						staticClass:this.reduceClass,
						props:{
							name:'expand_more'
						},
						on:{
							click:this.$_lexmis_reduce
						}
					}),
				])
				:null
		]);
	},
});
